import * as Types from "../../types";
import * as TypeHelper from "./TypeHelper";
import * as ExceptionHelper from "./ExceptionHelper";
import * as JsonHelper from "./JsonHelper";

export function numberCast(option: number | string | undefined, defaultValue: number): number {
    if (option === undefined) return defaultValue;
    if (typeof option === "number") return option;
    if (/^(([1-9][0-9]*(\.\d{1,2})?)|(0\.\d{1,2}))$/.test(option)) {
        return Number(option);
    }

    return ExceptionHelper.assertNumber(option);
}

export function stringCast(option: any): string {
    if (!TypeHelper.isStringWithNotEmpty(option)) return ExceptionHelper.assertString(option);
    return option;
}

export function booleanCast(option: boolean | undefined, defaultValue: boolean): boolean {
    if (option === undefined) return defaultValue;
    if (typeof option !== "boolean") ExceptionHelper.assertBoolean(option);
    return option;
}

export function stringOrBooleanStyleCast(option: string | boolean | undefined, defaultValue: string | null, trueValue?: string | null): string | null {
    if (option === undefined) return defaultValue;
    if (option === true) {
        if (trueValue === undefined) {
            return defaultValue;
        }
        else {
            return trueValue;
        }
    }
    if (option === false) return null;
    return option;
}

export function typeOrBooleanCast<T>(option: T | boolean | undefined, defaultValue: T | false, trueValue?: T | false, falseValue?: T | false): T | false {
    if (option === undefined) return defaultValue;
    if (option === true) {
        if (trueValue === undefined) {
            return defaultValue;
        }
        else {
            return trueValue;
        }
    }
    if (option === false) {
        if (falseValue === undefined) {
            return false;
        }
        else {
            return falseValue;
        }
    }
    return option;
}

export function undefinedCast<T>(option: T, defaultValue: T): T {
    if (option === undefined) return defaultValue;
    else return option;
}

export function stringOrUndefinedCast(option: any): string | undefined {
    if (option === undefined) return undefined;
    if (!TypeHelper.isStringWithNotEmpty(option)) return ExceptionHelper.assertString(option);
    return option;
}

export function jsonOrBooleanCast<T extends Types.JsonObject>(option: T | boolean | undefined, defaultValue: T | false, trueValue?: T | false, falseValue?: T | false): T | false {
    if (option === undefined) return defaultValue;
    if (option === true) {
        if (trueValue === undefined) {
            return defaultValue;
        }
        else {
            return trueValue;
        }
    }
    if (option === false) {
        if (falseValue === undefined) {
            return false;
        }
        else {
            return falseValue;
        }
    }
    if (defaultValue === false) return option;
    return JsonHelper.merge(defaultValue, option);
}

export function stringOrElementCast(option: any): string | Element {
    if (!TypeHelper.isStringOrElement(option)) return ExceptionHelper.assertNever(option);
    return option;
}

export function tupleStringOrElementCast(option: any): [string | Element, string | Element] {
    if (!(option instanceof Array)
        || option.length !== 2
        || !TypeHelper.isStringOrElement(option[0])
        || !TypeHelper.isStringOrElement(option[1])) return ExceptionHelper.assertNever(option);

    return <[string | Element, string | Element]>option;
}
